package network

import (
	"net"
	"sync"
	"log"
)

type TcpServer struct {
	mutex       sync.Mutex
	waitGroup   sync.WaitGroup
	listen  	net.Listener
	connections map[net.Conn]interface{}
}

func NewTcpServer(address string) *TcpServer {

	listen, err := net.Listen("tcp", address)
	if err != nil {
		panic(err)
	}

	return &TcpServer{
		listen:    	 listen,
		connections: make(map[net.Conn]interface{}),
	}
}

func (server *TcpServer) Start() error {

	log.Println("server start listen:", server.listen.Addr())

	for {
		conn, err := server.listen.Accept()
		if err != nil {
			server.Stop()
			return err
		}

		go server.handleConn(conn)
	}
}

func (server *TcpServer) Stop() {
	server.mutex.Lock()
	defer server.mutex.Unlock()

	for conn := range server.connections {
		conn.Close()
	}

	log.Println("server close")

	server.waitGroup.Wait()
}

func (server *TcpServer) handleConn(conn net.Conn) {
	server.waitGroup.Add(1)
	defer server.waitGroup.Done()

	if !server.addConn(conn) {
		conn.Close()
		return
	}

	defer server.delConn(conn)

	ReadMessage(conn, func(conn net.Conn, message *Message) {
		log.Println("message:", message.Code, string(message.Data))

		SendMessage(conn, message.Code, message.Data)
	})
}

func (server *TcpServer) addConn(conn net.Conn) bool {
	server.mutex.Lock()
	defer server.mutex.Unlock()

	if server.connections == nil {
		return false
	}

	log.Println("clinet connect")

	server.connections[conn] = nil

	return true
}

func (server *TcpServer) delConn(conn net.Conn) {
	server.mutex.Lock()
	defer server.mutex.Unlock()

	if server.connections != nil {
		delete(server.connections, conn)
		conn.Close()
	}

	log.Println("clinet close")
}